home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / news / misc / eep / eep1_9 / eepmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-21  |  35.6 KB  |  1,128 lines

  1. /*  This module contains the code for the user interface for eep.  */
  2.  
  3. #include    <stdio.h>
  4. #include    <string.h>
  5. #include    <curses.h>
  6.  
  7. #ifdef UNIX
  8. #include    <ctype.h>
  9. #include    <signal.h>
  10. #include    <fcntl.h>
  11. #include    <termio.h>  /* sometimes this is included in curses.h */
  12. #endif /* UNIX */
  13.  
  14. #ifdef ANSI
  15. #include <stdlib.h>
  16. #else
  17. #define void int
  18. extern char *malloc();
  19. #endif /* ANSI */
  20.  
  21. #include    "eep.h"          /* local changes */
  22.  
  23. extern int    qcompare();    /* sort alphabetically */
  24. extern int    icompare();    /* sort by index */
  25. extern int    scompare();    /* sort by subscription status */
  26. extern char   *shift_lower();    /* see eepmisc.c */
  27. extern char   *wallop();     /* see eepmisc.c */
  28. extern char   buffer[],      /* general purpose line buffer */
  29.               tmp[];
  30.  
  31. extern struct  actif *act[];    /* main data structure */
  32.  
  33. extern int    i_active;    /* index into arrays */
  34. extern int    c_active;    /* number of lines in act array */
  35. extern int    eepoint;     /* pointer switch */
  36. extern int    bog_count;   /* bogus newsgroups */
  37. extern int    sub_count;   /* subscribed newsgroups */
  38. extern int    curses_ok;   /* can we use curses yet? */
  39. extern int    del_unsub;   /* delete unsubscribed groups */
  40.  
  41. extern char   *home;       /* HOME directory */
  42. extern FILE   *fnewsrc;    /* .newsrc.eep */
  43.  
  44. /* The levels array contains the Head pointers which control the
  45. linked lists of newsgroups grouped by their "depth" in the
  46. hierarchy, and sorted alphabetically.  E.g. alt, sci, soc are 
  47. level 0, alt.pagan, sci.physics are level 1 and so on. */
  48.  
  49. extern struct actif *levels[];  /* keep track of levels with this array */
  50. extern struct actif *aptr;    /* temporary pointer */
  51. extern int    i_levels;    /* index into array */
  52.  
  53. /* More Global variables */
  54.  
  55. int    scrnpos = 0;            /* position of highlight on screen */
  56. int    current = 0;            /* matching highlight in data structure */
  57. int    alphabetized = FALSE;   /* flag showing if sorted */
  58. int    top = 0;                /* data element on top of screen */
  59. int    direction = 0;          /* 0 means down, 1 means up */
  60. int    eeplines = 0;           /* number of lines on screen */
  61. int    eepcolumns = 0;         /* columns on screen */
  62. int    eeppage = EEPPAGE;      /* page size for scrolling */
  63. int    desc_changed = FALSE;   /* has a description changed? */
  64. int    namecols;               /* cols to use for name */
  65. int    desccols;               /* cols to use for name */
  66. int    colchunk;               /* size of pan left or right */
  67.  
  68. /* Define two buffers: tbuf and tbufsave.  tbuf is used for changing
  69. the keyboard modes, while tbufsave is used to restore them. */
  70.  
  71. #ifdef UNIX
  72. struct termio tbuf;
  73. struct termio tbufsave;
  74. int    tbuf_ok = FALSE;  /* is tbufsave valid? */
  75. #endif /* UNIX */
  76.  
  77. WINDOW    *over;        /* used for on-screen help window etc. */
  78. void      showhelp();   /* forward declaration */
  79. void      showlist();
  80.  
  81. /* pad() -- this function will take a pointer to a string and a 
  82. numeric argument, and will pad the string with spaces to reach
  83. the desired length.  If the string is too long, it will be 
  84. truncated to fit.  The function will return a pointer to a
  85. static buffer that will contain the padded
  86. string (or original if it's long enough already). 
  87. If str is a NULL pointer, we'll return spaces only. */
  88.  
  89. char    *pad(str,len)
  90. char    *str;
  91. int    len;
  92. {
  93. static char mybuf[BUFSIZE];
  94.  
  95. int    count;
  96.     mybuf[0] = '\0';
  97.     if (len >= BUFSIZE) return(mybuf); /* safety */
  98.     /* In case we are passed a NULL pointer... */
  99.     if (str == (char *) NULL) {
  100.         mybuf[0] = '\0';
  101. /*        while (strlen(mybuf) < len) strcat(mybuf," "); */
  102.         count = 0;
  103.         while (count++ < len) strcat(mybuf," ");
  104.         return(mybuf);
  105.     }
  106.     if (strlen(str) >= len) {
  107.         strncpy(mybuf,str,len);
  108.         return(mybuf);
  109.     }
  110.     strcpy(mybuf,str);
  111. /*    while (strlen(mybuf) < len) */
  112.     count = len;
  113.     while (count-- > 0)
  114.         strcat(mybuf," ");
  115.     return(mybuf);
  116. }
  117.  
  118. /* newsmain()  -- this provides the mainline user interface. */
  119.  
  120. void    newsmain()
  121. {
  122.  
  123. char    *ptr;
  124. char    search[BUFSIZE];    /* search string buffer */
  125. int     found = FALSE;      /* flag to say we've found something */
  126. int     quit = FALSE;       /* flag used when ready to quit */
  127. int     position;              /* used when searching */
  128. int     counter;            /* used when counting */
  129. int     ch;                 /* input character */
  130.  
  131.     initscr();    /* set up for curses */
  132.     curses_ok = TRUE;
  133.     if ((ptr = (char *)getenv("LINES")) != (char *)NULL)
  134.         eeplines = atoi(ptr);
  135.     if ((ptr = (char *)getenv("COLUMNS")) != (char *)NULL)
  136.         eepcolumns = atoi(ptr);
  137.  
  138.     if (eeplines <= 0)
  139.         eeplines = LINES;
  140.     if (eepcolumns <= 0)
  141.         eepcolumns = COLS;
  142.     if (eeplines <= 0)
  143.         eeplines = EEPLINES;
  144.     if (eepcolumns <= 0)
  145.         eepcolumns = EEPCOLUMNS;
  146.     if ((eeplines < 19) || (eepcolumns < 80)) {
  147.         fprintf(stderr,
  148.             "\r\nSorry, EEP needs at least 19 lines by 80 columns.\n\r");
  149.         cleanup();
  150.     }
  151.     eeppage = eeplines - 2;
  152.     colchunk = eepcolumns / 10;
  153.     namecols = 0.35 * eepcolumns;
  154.     desccols = 0.55 * eepcolumns;
  155.  
  156.     raw();
  157.     noecho();
  158.     nonl();
  159.     keypad(stdscr,TRUE);
  160.     erase();    /* clear screen */
  161.  
  162. #ifdef UNIX
  163.     idlok(stdscr,TRUE);
  164.     /* POSIX: tcgetattr(0, &tbuf); */
  165.     if (ioctl(0, TCGETA, &tbuf) >= 0) {
  166.         tbufsave = tbuf; /* save the old settings */
  167.         tbuf_ok = TRUE;
  168.         tbuf.c_iflag &= ~(IXON | IXOFF); /* disable ^S & ^Q */
  169.         ioctl(0, TCSETAF, &tbuf); /* POSIX: tcsetattr(0, X???WAIT, &tbuf); */
  170.     }
  171. #endif /* UNIX */
  172.  
  173.     showlist(0,0);
  174.     while (quit == FALSE) {
  175.     ch = getch();
  176.     switch(ch) {
  177.         case 'q':    /* quit */
  178.         case 'Q':
  179.         case '\033':    /* ESCAPE by itself */
  180.         case '\003':    /* for those who like ^C */
  181.         case '\177':    /* for those who like INTR */
  182. #ifdef KEY_ABORT
  183.         case KEY_ABORT:
  184. #endif
  185.             move(eeplines-1,0);
  186.             deleteln();
  187.             addstr("Do you want to quit without saving your changes? [n]: ");
  188.             refresh();
  189.             if (tolower(getch()) == (int) 'y') quit = TRUE;
  190.             deleteln();
  191.             move(scrnpos,0);
  192.             refresh();
  193.             break;
  194.  
  195.         case '?':    /* on-line help */
  196.         case 'h':
  197.         case 'H':
  198.         case KEY_F(1):
  199. #ifdef KEY_HELP
  200.         case KEY_HELP:
  201. #endif
  202.             over = newwin(22,60,1,15);
  203.             if (!eepoint) wstandout(over);
  204.             box(over,'\0','\0');
  205.             if (!eepoint) wstandend(over);
  206.             wmove(over,2,5);
  207.             wstandout(over);
  208.             waddstr(over," EEP! v1.9: helpful .newsrc editor ");
  209.             wstandend(over);
  210.             wmove(over,3,5);
  211.             waddstr(over,"by Paul Gillingwater, paul@actrix.co.at");
  212.             wmove(over,6,5);
  213.             waddstr(over,":   Pick by number    /   Search");
  214.             wmove(over,7,5);
  215.             waddstr(over,"a   (un)Alphabetise   b   Bottom of file");
  216.             wmove(over,8,5);
  217.             waddstr(over,"c   Catch up          e   Edit description ");
  218.             wmove(over,9,5);
  219.             waddstr(over,"i   Show info         j   Next line");
  220.             wmove(over,10,5);
  221.             waddstr(over,"k   Previous line     n   Search next");
  222.             wmove(over,11,5);
  223.             waddstr(over,"o   Over-subscribe    p   Pointer change");
  224.             wmove(over,12,5);
  225.             waddstr(over,"q   Quit, no save     r   Redraw screen");
  226.             wmove(over,13,5);
  227.             waddstr(over,"s   Subscribe         t   Top of file");
  228.             wmove(over,14,5);
  229.             waddstr(over,"u   Unsubscribe       v   View subjects");
  230.             wmove(over,15,5);
  231.             waddstr(over,"x   Save and exit ");
  232.             wmove(over,16,5);
  233.             waddstr(over,"^D  Page down         ^U  Page up");
  234.             wmove(over,17,5);
  235.             waddstr(over,"^S  EMACS Search      ^R  Reverse search");
  236.             wmove(over,18,5);
  237.             waddstr(over,".   (un)Mark group    m   Move marked groups");
  238.             sprintf(buffer,"There are %d subscribed newsgroups.",sub_count);
  239.             wmove(over,20,5);
  240.             waddstr(over,buffer);
  241.             wmove(over,21,5);
  242.             wstandout(over);
  243.             waddstr(over," Press SPACE BAR to exit from help ");
  244.             wstandend(over);
  245.             wrefresh(over);
  246.             ch = wgetch(over);
  247.             delwin(over);
  248.             touchwin(stdscr);
  249.             refresh();
  250.             break;
  251.  
  252.         case '<':
  253. #ifdef KEY_LEFT
  254.         case KEY_LEFT:
  255. #endif
  256.             if (namecols >= colchunk)
  257.             {
  258.                 namecols -= colchunk;
  259.                 desccols += colchunk;
  260.                 showlist(current,0);
  261.                 break;
  262.             }
  263.             break;
  264.  
  265.         case '>':
  266. #ifdef KEY_RIGHT
  267.         case KEY_RIGHT:
  268. #endif
  269.             if (desccols >= colchunk)
  270.             {
  271.                 namecols += colchunk;
  272.                 desccols -= colchunk;
  273.                 showlist(current,0);
  274.                 break;
  275.             }
  276.             break;
  277.  
  278.         case 'e':    /* edit newsgroup description */
  279.         case 'E':
  280. #ifdef KEY_EDIT
  281.         case KEY_EDIT:
  282. #endif
  283.             aptr = act[current];
  284.             if (aptr == (struct actif *)NULL) break;
  285.             move(eeplines - 1,0);
  286.             deleteln();
  287.             printw("Enter new description: ");
  288.             refresh();
  289.             getbuf(buffer,60);
  290.             if (strlen(buffer) > 0) {
  291.                 ptr = (char *)wallop(strlen(buffer)+1);
  292.                 if (ptr == (char *)NULL) {
  293.                     fprintf(stderr, "Fatal memory allocation error.\n");
  294.                     cleanup();
  295.                 }
  296.                 strcpy(ptr,buffer);
  297.                 aptr->desc = ptr;
  298.                 desc_changed = TRUE;
  299.             }
  300.             showlist(current,0);
  301.             break;
  302.  
  303.         case ':':    /* enter number */
  304.             move(eeplines - 1,0);
  305.             deleteln();
  306.             addch(':');
  307.             refresh();
  308.             getbuf(buffer,10);
  309.             position = atoi(buffer);
  310.             if ((position <= 0) || (position > c_active)) {
  311.                 move(eeplines - 1,0);
  312.                 printw("Newsgroups available: %d ",c_active);
  313.                 refresh();
  314.                 sleep(2);
  315.                 deleteln();
  316.                 move(scrnpos,0);
  317.                 refresh();
  318.                 break;
  319.             }
  320.             current = position - 1;
  321.             showlist(current,0);
  322.             break;
  323.  
  324.         case '.':    /* mark group -- used to move later */
  325. #ifdef KEY_MOVE
  326.         case KEY_MOVE:
  327. #endif
  328.             aptr = act[current];
  329.             if (aptr->mark == 0)
  330.                 aptr->mark = 1;
  331.             else
  332.                 aptr->mark = 0;
  333.             if (direction == 0)
  334.                 goto    scroll_down;
  335.             else
  336.                 goto    scroll_up;
  337.             break;
  338.  
  339.         case 'm':    /* move marked groups */
  340.         case 'M':
  341. #ifdef KEY_SMOVE
  342.         case KEY_SMOVE:
  343. #endif
  344.             i_active = 0;
  345.             while (i_active < c_active) {
  346.                 if ((aptr = act[i_active]) == (struct actif *)NULL) {
  347.                     i_active++;
  348.                     continue;
  349.                 }
  350.                 if (aptr->mark == 0) {
  351.                     i_active++;
  352.                     continue;
  353.                 }
  354.                 aptr->position = current;
  355.                 aptr->mark = 0;
  356.                 i_active++;
  357.             }
  358.             qsort( act, (unsigned) c_active, 
  359.                     (unsigned) sizeof(act[0]), icompare);
  360.             alphabetized = FALSE;
  361.  
  362.             /* Renumber to match current order. */
  363.             i_active = 0;
  364.             while (i_active < c_active) {
  365.                 if ((aptr = act[i_active]) == (struct actif *)NULL) {
  366.                     i_active++;
  367.                     continue;
  368.                 }
  369.                 aptr->position = ++i_active;
  370.             }
  371.             showlist(current,0);
  372.             break;
  373.  
  374.         case 'r':    /* redraw */
  375.         case 'R':    /* redraw */
  376.         case '\014':    /* form feed ^L */
  377. #ifdef KEY_REFRESH
  378.         case KEY_REFRESH:
  379. #endif
  380.             touchwin(stdscr);
  381.             clearok(stdscr,TRUE);
  382.             refresh();
  383.             break;
  384.  
  385.         case 'v':    /* view newsgroup */
  386.         case '=':    /* view newsgroup */
  387.         case '\r':
  388.         case '\n':    /* new line to select a group */
  389.             if ((aptr = act[current]) == (struct actif *)NULL) 
  390.                 break;
  391.             eepview(aptr->name);
  392.             showlist(current,0);
  393.             break;
  394.  
  395.         case 'i':
  396.             if ((aptr = act[current]) == (struct actif *)NULL) 
  397.                 break;
  398.             over = newwin(18,65,0,5);
  399.             if (!eepoint) wstandout(over);
  400.             box(over,'\0','\0');
  401.             if (!eepoint) wstandend(over);
  402.             wmove(over,2,5);
  403.             wprintw(over,"Number: %d",current + 1);
  404.             wmove(over,3,5);
  405.             wprintw(over,"Name: %.50s",pad(aptr->name,50));
  406.             wmove(over,4,5);
  407.             wprintw(over,"Desc: %.50s",pad(aptr->desc,50));
  408.             wmove(over,6,5);
  409.             wprintw(over,"This news group is ");
  410.             switch(aptr->flag) {
  411.             case 'y':
  412.                 wprintw(over,"Active.");
  413.                 break;
  414.             case 'n':
  415.                 wprintw(over,"Not Active.");
  416.                 break;
  417.             case 'm':
  418.                 wprintw(over,"Moderated.");
  419.                 break;
  420.             default:
  421.                 wprintw(over,"Invalid.");
  422.             }
  423.             wmove(over,7,5);
  424.             wprintw(over,"Your .newsrc says this is ");
  425.             switch(aptr->status) {
  426.             case ':':
  427.                 wprintw(over,"Subscribed to.");
  428.                 break;
  429.             case '!':
  430.                 wprintw(over,"Not Subscribed to.");
  431.                 break;
  432.             default:
  433.                 wprintw(over,"Not valid.");
  434.                 break;
  435.             }
  436.             if (aptr->hi > 0) {
  437.                 wmove(over,9,5);
  438.                 wprintw(over,"Active high message is %ld",
  439.                     aptr->hi);
  440.                 wmove(over,11,5);
  441.                 wprintw(over,"Messages already read by you include:");
  442.                 wmove(over,12,5);
  443.                 wprintw(over,"%s",pad(aptr->hilo,50));
  444.             }
  445.             wmove(over,17,5);
  446.             wstandout(over);
  447.             waddstr(over," Press SPACE BAR to continue ");
  448.             wstandend(over);
  449.             wrefresh(over);
  450.             ch = wgetch(over);
  451.             delwin(over);
  452.             touchwin(stdscr);
  453.             refresh();
  454.             break;
  455.  
  456.         case '/':    /* search */
  457.         case 'n':    /* search for next occurence */
  458.         case 'N':
  459. #ifdef KEY_FIND
  460.         case KEY_FIND:
  461.             if (ch == KEY_FIND) ch = '/';
  462. #endif
  463.             if (ch == '/') {
  464.                 move(eeplines - 1,0);
  465.                 deleteln();
  466.                 addch('/');
  467.                 refresh();
  468.                 getbuf(tmp,60);
  469.                 if (strlen(tmp) == 0) {
  470.                     if (!found) {
  471.                         beep();   /* nothing to find */
  472.                         deleteln();
  473.                         move(scrnpos,0);
  474.                         refresh();
  475.                         break;
  476.                     }
  477.                 } else strcpy(search,tmp);
  478.             }
  479.             if ((ch == 'n') || (ch == 'N')) {
  480.                 if (!found) {
  481.                     beep();   /* nothing to find */
  482.                     move(scrnpos,0);
  483.                     refresh();
  484.                     break;
  485.                 }
  486.             }
  487.             found = FALSE;
  488.             /* make it lower case for searching */
  489.             strcpy(search,shift_lower(search));
  490.             if (direction == 0) { /* search downwards */
  491.                 position = current + 1;    /* track progress */
  492.                 if (position >= c_active) position = 0;
  493.               
  494.                 while (position != current) {
  495.                     aptr = act[position];
  496.                     if (aptr != (struct actif *)NULL) {
  497.                         if (in_string(shift_lower(aptr->name),search,0) >= 0 ||
  498.                             in_string(shift_lower(aptr->desc),search,0) >= 0) {
  499.                             /* found match */
  500.                             found = TRUE;
  501.                             current = position;
  502.                             showlist(current,0);
  503.                             break;
  504.                         }
  505.                     }
  506.                     position++;
  507.                     if (position >= c_active) position = 0;
  508.                 }
  509.             } else {
  510.                 position = current - 1;    /* track progress */
  511.                 if (position < 0) position = c_active - 1;
  512.               
  513.                 while (position != current) {
  514.                     aptr = act[position];
  515.                     if (aptr != (struct actif *)NULL) {
  516.                         if (in_string(shift_lower(aptr->name),search,0) >= 0 ||
  517.                             in_string(shift_lower(aptr->desc),search,0) >= 0) {
  518.                             /* found match */
  519.                             found = TRUE;
  520.                             current = position;
  521.                             showlist(current,0);
  522.                             break;
  523.                         }
  524.                     }
  525.                     position--;
  526.                     if (position < 0) position = c_active - 1;
  527.                 }
  528.             }
  529.             if (!found) {
  530.                 beep();
  531.                 move(scrnpos,0);
  532.                 refresh();
  533.             }
  534.             break;
  535.  
  536.         /* EMACS style searching */
  537.  
  538.         case '\022':   /* ^R */
  539.         case '\023':   /* ^S */
  540. #ifdef KEY_SFIND
  541.         case KEY_SFIND:
  542.             if (ch == KEY_SFIND) ch = '\022';
  543. #endif
  544.             do_search(ch);       /* eepmisc.c */
  545.             break;
  546.  
  547.         case 't':
  548.         case 'T':
  549.         case '^':    /* top of list */
  550. #ifdef KEY_HOME
  551.         case KEY_HOME:
  552. #endif
  553. #ifdef KEY_BEG
  554.         case KEY_BEG:
  555. #endif
  556.             current = 0;
  557.             scrnpos = 0;
  558.             showlist(current,0);
  559.             break;
  560.  
  561.         case 'b':
  562.         case 'B':
  563.         case '$':    /* bottom of list */
  564. #ifdef KEY_SHOME
  565.         case KEY_SHOME:
  566. #endif
  567. #ifdef KEY_END
  568.         case KEY_END:
  569. #endif
  570.             current = c_active - 1;
  571.             scrnpos = eeplines - 2;
  572.             showlist(current,0);
  573.             break;
  574.  
  575.         case 'a':    /* change sorting order */
  576.         case 'A':
  577.             move(eeplines-1,0);
  578.             deleteln();
  579.             if (alphabetized) {
  580.                 addstr("Do you wish to sort in .newsrc order? [n]: ");
  581.                 refresh();
  582.                 if (tolower(getch()) != (int) 'y') {
  583.                     deleteln();
  584.                     move(scrnpos,0);
  585.                     refresh();
  586.                     break;
  587.                 }
  588.                 qsort( act, (unsigned) c_active, 
  589.                     (unsigned) sizeof(act[0]), icompare);
  590.                 alphabetized = FALSE;
  591.             } else {
  592.                 addstr("Do you wish to sort alphabetically? [n]: ");
  593.                 refresh();
  594.                 if (tolower(getch()) != (int) 'y') {
  595.                     deleteln();
  596.                     move(scrnpos,0);
  597.                     refresh();
  598.                     break;
  599.                 }
  600.                 qsort( act, (unsigned) c_active, 
  601.                     (unsigned) sizeof(act[0]), qcompare);
  602.                 alphabetized = TRUE;
  603.             }
  604.             deleteln();
  605.             move(scrnpos,0);
  606.             showlist(current,0);
  607.             break;
  608.  
  609.         case 'o':
  610.         case 'O':    /* order (arrange subscribed groups at top */
  611.             move(eeplines-1,0);
  612.             deleteln();
  613.             addstr("Move all subscribed groups to top? [n]: ");
  614.             refresh();
  615.             if (tolower(getch()) == (int) 'y') {
  616.                 qsort( act, (unsigned) c_active, 
  617.                     (unsigned) sizeof(act[0]), scompare);
  618.                 alphabetized = FALSE;
  619.                 deleteln();
  620.                 showlist(current,0);
  621.                 break;
  622.             }
  623.             deleteln();
  624.             move(scrnpos,0);
  625.             refresh();
  626.             break;
  627.  
  628.         case '+':    /* subscribe to this newsgroup */
  629.         case 's':
  630.         case 'S':
  631. #ifdef KEY_MARK
  632.         case KEY_MARK:
  633. #endif
  634.             aptr = act[current];
  635.             /* check if group is valid */
  636.             if ((aptr->flag == 'y') ||
  637.                 (aptr->flag == 'm')) {
  638.                 aptr->status = ':';
  639.                 sub_count++;
  640.                 move(scrnpos,2);
  641.                 standout();
  642.                 addch('+');
  643.                 standend();
  644.                 move(scrnpos,0);
  645.             } else {
  646.                 move(eeplines - 1,0);
  647.                 printw("Not a valid newsgroup -- cannot subscribe");
  648.                 refresh();
  649.                 sleep(2);
  650.                 deleteln();
  651.                 move(scrnpos,0);
  652.             }
  653.             refresh();
  654.             if (direction == 0)
  655.                 goto    scroll_down;
  656.             else
  657.                 goto    scroll_up;
  658.             break;
  659.  
  660.         case '-':    /* unsubscribe to this newsgroup */
  661.         case 'u':    /* also means unjoin */
  662.         case 'U':
  663. #ifdef KEY_SMARK
  664.         case KEY_SMARK:
  665. #endif
  666.             aptr = act[current];
  667.             /* check if group is valid */
  668.             aptr->status = '!';
  669.             if (sub_count > 0) sub_count--;
  670.             if ((aptr->flag == 'y') ||
  671.                 (aptr->flag == 'm')) {
  672.                 move(scrnpos,2);
  673.                 standout();
  674.                 addch(' ');
  675.                 standend();
  676.                 move(scrnpos,0);
  677.             } else {
  678.                 move(eeplines - 1,0);
  679.                 printw("Not a valid newsgroup -- unsubscribing anyway");
  680.                 refresh();
  681.                 sleep(2);
  682.                 deleteln();
  683.                 move(scrnpos,0);
  684.             }
  685.             refresh();
  686.             if (direction == 0)
  687.                 goto    scroll_down;
  688.             else
  689.                 goto    scroll_up;
  690.             break;
  691.  
  692.         case ' ':
  693.         case 'j':
  694.         case 'J':    /* join */
  695.         case '\016':    /* for emacs users */
  696. #ifdef KEY_DOWN
  697.         case KEY_DOWN:
  698. #endif
  699. scroll_down:
  700.         /* Don't move if we're at the end. */
  701.             if (current == c_active - 1) {
  702.                 beep();
  703.                 break;
  704.             }
  705.             direction = 0;
  706.             /* remove highlights by redrawing line */
  707.             aptr = act[current];
  708.             move(scrnpos,0);
  709.             if (!eepoint) standend();
  710.             if (aptr->mark == 0)
  711.                 printw("  ");
  712.             else
  713.                 printw("* ");
  714.             switch(aptr->status) {
  715.             case ':':    printw("+"); /* subscribed */
  716.                     break;
  717.             case '!':    printw(" "); /* unsubscribed */
  718.                     break;
  719.             default:     printw("?"); /* mystery! */
  720.             }
  721.             if (!eepoint) {
  722.                 printw("%.*s ", namecols, pad(aptr->name, namecols));
  723.                 printw("%.*s ", desccols, pad(aptr->desc, desccols));
  724.             }
  725.             refresh();
  726.             current++;
  727.             if (++scrnpos == eeplines - 1) { /* scroll up */
  728.                 move(0,0);
  729.                 deleteln();
  730.                 move(eeplines - 2,0);
  731.                 insertln();
  732.                 refresh();
  733.                 scrnpos = eeplines - 2;
  734.                 top++;
  735.             };
  736.             /* Now paint our new position */
  737.             move(scrnpos,0);
  738.             aptr = act[current];
  739.             if (!eepoint) standout();
  740.             if (aptr->mark == 0)
  741.                 printw("-");
  742.             else
  743.                 printw("*");
  744.             switch(aptr->status) {
  745.             case ':':    printw(">+"); /* subscribed */
  746.                     break;
  747.             case '!':    printw("> "); /* unsubscribed */
  748.                     break;
  749.             default:    printw(">?"); /* mystery! */
  750.             }
  751.             printw("%.*s ", namecols, pad(aptr->name, namecols));
  752.             printw("%.*s ", desccols, pad(aptr->desc, desccols));
  753.             if (!eepoint) standend();
  754.             move(scrnpos,0);
  755.             refresh();
  756.             break;
  757.  
  758.         case 'k':
  759.         case 'K':
  760.         case '\010':    /* backspace */
  761.         case '\020':    /* for emacs users */
  762. #ifdef KEY_UP
  763.         case KEY_UP:
  764. #endif
  765. scroll_up:
  766.         /* Don't move if we're at the top. */
  767.             if (current == 0) {
  768.                 beep();
  769.                 break;
  770.             }
  771.             direction = 1; /* now going up */
  772.             move(scrnpos,0);
  773.             aptr = act[current];
  774.             if (!eepoint) standend();
  775.             if (aptr->mark == 0)
  776.                 printw("  ");
  777.             else
  778.                 printw("* ");
  779.             switch(aptr->status) {
  780.             case ':':    printw("+"); /* subscribed */
  781.                     break;
  782.             case '!':    printw(" "); /* unsubscribed */
  783.                     break;
  784.             default:    printw("?"); /* mystery! */
  785.             }
  786.             if (!eepoint) {
  787.                 printw("%.*s ", namecols, pad(aptr->name, namecols));
  788.                 printw("%.*s ", desccols, pad(aptr->desc, desccols));
  789.             }
  790.             move(scrnpos,0);
  791.             refresh();
  792.             current--;
  793.             if (--scrnpos == -1) {
  794.                 move(eeplines - 2,0);
  795.                 deleteln();
  796.                 move(0,0);
  797.                 insertln();
  798.                 refresh();
  799.                 move(0,0);
  800.                 scrnpos = 0;
  801.                 if (top > 0) top--;
  802.             }; /* cause scroll */
  803.             move(scrnpos,0);
  804.             aptr = act[current];
  805.             if (!eepoint) standout();
  806.             if (aptr->mark == 0)
  807.                 printw("-");
  808.             else
  809.                 printw("*");
  810.             switch(aptr->status) {
  811.             case ':':    printw(">+"); /* subscribed */
  812.                     break;
  813.             case '!':    printw("> "); /* unsubscribed */
  814.                     break;
  815.             default:     printw(">?"); /* mystery! */
  816.             }
  817.             printw("%.*s ", namecols, pad(aptr->name, namecols));
  818.             printw("%.*s ", desccols, pad(aptr->desc, desccols));
  819.             if (!eepoint) standend();
  820.             move(scrnpos,0);
  821.             refresh();
  822.             break;
  823.  
  824.  
  825.         case '\004':    /* ^D */
  826.         case '\006':    /* ^F */
  827. #ifdef KEY_NPAGE
  828.         case KEY_NPAGE: /* next page */
  829. #endif
  830.             /* If a pagedown will go past the end
  831.             of the list, simply position at the end. */
  832.  
  833.             if (current == c_active - 1) {
  834.                 beep();
  835.                 break;
  836.             }
  837.             direction = 0;
  838.             if ((current += eeppage) >= c_active) {
  839.                 current = c_active - 1;
  840.                 if ((c_active - current) < (eeplines - 2))
  841.                     scrnpos = eeplines - 2;
  842.             } else  if (scrnpos + eeppage < eeplines - 2)
  843.                     scrnpos += eeppage; 
  844.             showlist(current,0);
  845.             break;
  846.  
  847.         case '\025':    /* ^U */
  848.         case '\002':    /* ^B */
  849. #ifdef KEY_PPAGE
  850.         case KEY_PPAGE: /* previous page */
  851. #endif
  852.             if (current == 0) {
  853.                 beep();
  854.                 break;
  855.             }
  856.             direction = 1;
  857.             if ((current -= eeppage) < 0) {
  858.                 current = 0;
  859.                 scrnpos = 0;
  860.             } else  if ((scrnpos - eeppage) >= 0)
  861.                     scrnpos -= eeppage;
  862.             showlist(current,0);
  863.             break;
  864.  
  865.         case 'p':   /* change type of pointer */
  866.         case 'P':
  867.             if (eepoint) eepoint = FALSE;
  868.             else eepoint = TRUE;
  869.             showlist(current,0);
  870.             break;
  871.  
  872.         case 'c':   /* catch up */
  873.         case 'C':
  874.             aptr = act[current];
  875.             /* only if it's a real news group */
  876.             if (aptr->hi <= 0) {
  877.                 if (direction == 0)
  878.                     goto    scroll_down;
  879.                 else
  880.                     goto    scroll_up;
  881.             }
  882.             if ((aptr->flag == 'y') ||
  883.                 (aptr->flag == 'm') ||
  884.                 (aptr->flag == 'n')) {
  885.                 move(eeplines-1,0);
  886.                 deleteln();
  887.                 addstr("Catch up this news group? [n]: ");
  888.                 refresh();
  889.                 if (tolower(getch()) == 'y') {
  890.                     sprintf(buffer,"1-%ld", aptr->hi);
  891.                     if (aptr->hilo != (char *)NULL) {
  892.                         if (aptr->hilo[0] == '0')
  893.                             sprintf(buffer,"0-%ld", aptr->hi);
  894.                     }
  895.                     aptr->hilo = (char *)wallop(strlen(buffer)+1);
  896.                     if (aptr->hilo == (char *)NULL) {
  897.                         fprintf(stderr, "Fatal memory allocation error.\n");
  898.                         exit(2);
  899.                     }
  900.                     strcpy(aptr->hilo,buffer);
  901.                     deleteln();
  902.                     move(eeplines-1,0);
  903.                     printw("High message now %ld", aptr->hi);
  904.                 } else deleteln();
  905.                 move(scrnpos,0);
  906.                 refresh();
  907.             }
  908.             if (direction == 0)
  909.                 goto    scroll_down;
  910.             else
  911.                 goto    scroll_up;
  912.             break;
  913.  
  914.         case 'x':   /* write the local .newsrc and exit */
  915.         case 'X':
  916. #ifdef KEY_EXIT
  917.         case KEY_EXIT:
  918. #endif /* KEY_EXIT */
  919.             move(eeplines-1,0);
  920.             deleteln();
  921.             if (fnewsrc == (FILE *) NULL) {
  922.                 addstr("Couldn't open .newsrc.eep -- write failed.");
  923.                 refresh();
  924.                 break;
  925.             }
  926.             addstr("Do you want to save and exit? [n]: ");
  927.             refresh();
  928.             if (tolower(getch()) != (int) 'y') {
  929.                 deleteln();
  930.                 move(scrnpos,0);
  931.                 refresh();
  932.                 break;
  933.             }
  934.             if (bog_count > 0) {
  935.                 move(eeplines-1,0);
  936.                 deleteln();
  937.                 addstr("Delete bogus groups from your .newsrc? [n]: ");
  938.                 refresh();
  939.                 if (tolower(getch()) != (int) 'y') bog_count = 0;
  940.             }
  941.             deleteln();
  942.             position = 0;
  943.             counter = 0;
  944.             while (position < c_active) {
  945.                 aptr = act[position];
  946.                 if ((aptr->flag == '\0') ||
  947.                     (aptr->status == '\0') ||
  948.                     (aptr->name == (char *)NULL)) {
  949.             /* must be bogus -- shall we forget it? */
  950.                     if (bog_count != 0) {
  951.                         position++;
  952.                         continue;
  953.                     }
  954.                 }
  955.  
  956.                 if (del_unsub) { /* delete unsubscribed newsgroups */
  957.                     if (aptr->status == '!') {
  958.                         position++;
  959.                         continue;
  960.                     }
  961.                 }
  962.  
  963.                 fprintf(fnewsrc,"%s",
  964.                     aptr->name);
  965.                 if (aptr->status == ':') {
  966.                     fprintf(fnewsrc,": ");
  967.                 } else {
  968.                     fprintf(fnewsrc,"! ");
  969.                 }
  970.                 if (aptr->hilo != (char *)NULL) {
  971.                     fprintf(fnewsrc,"%s", aptr->hilo);
  972.                 }
  973.                 fprintf(fnewsrc,"\n");
  974.                 counter++;
  975.                 position++;
  976.                 if (counter % 100 == 0) {
  977.                     move(eeplines-1,0);
  978.                     printw("%d",counter);
  979.                     refresh();
  980.                 }
  981.             }
  982.             fclose(fnewsrc);
  983.  
  984.             printf("\rTotal of %d lines written.\r\n",counter);
  985.             if (bog_count > 0) {
  986.                 if (bog_count == 1)
  987.                     printf("There was 1 bogus newsgroup deleted.\r\n");
  988.                 else
  989.                     printf("There were %d bogus newsgroups deleted.\r\n",
  990.                         bog_count);
  991.             }
  992.  
  993.             fnewsrc = (FILE *) NULL;
  994.             if (home != (char *)NULL) {
  995.                 sprintf(tmp, "%s/%s", home, NEWSRC);
  996.                 sprintf(buffer, "%s/%s.old", home, NEWSRC);
  997.             } else {
  998.                 sprintf(tmp, NEWSRC);   
  999.                 sprintf(buffer, "%s.old", NEWSRC);   
  1000.             }
  1001. #ifdef UNIX
  1002.  
  1003. /* Narrative: we rename the current .newsrc to .newsrc.old -- but
  1004.  * first we unlink any existing .newsrc.old.  We have just written
  1005.  * the modified .newsrc to .newsrc.new, and now we rename it to
  1006.  * replace the .newsrc -- which should be safely backed-up.
  1007.  */
  1008.  
  1009.             unlink(buffer);    /* don't care about errors */
  1010.  
  1011.             if (link(tmp,buffer) < 0) {
  1012.                 fprintf(stderr,"[1] .newsrc not replaced.");
  1013.                 break;
  1014.             }
  1015.             if (unlink(tmp) < 0) {
  1016.                 fprintf(stderr,"[2] .newsrc not replaced.");
  1017.                 break;
  1018.             }
  1019.             if (home != (char *)NULL)
  1020.                 sprintf(buffer, "%s/.newsrc.eep", home);
  1021.             else
  1022.                 sprintf(buffer, ".newsrc.eep");
  1023.  
  1024.             if (link(buffer,tmp) < 0) {
  1025.                 fprintf(stderr,"[3] .newsrc not replaced.");
  1026.                 break;
  1027.             }
  1028.             if (unlink(buffer) < 0) {
  1029.                 fprintf(stderr,"[4] .newsrc not replaced.");
  1030.                 break;
  1031.             }
  1032. #endif /* UNIX */
  1033.             noraw();
  1034.             return;
  1035.             break;
  1036.         }
  1037.     }
  1038.     move(eeplines - 1,0);
  1039.     clrtoeol();
  1040.     refresh();
  1041.     noraw();
  1042. }
  1043.  
  1044. /*
  1045.  * showlist() -- display list of newsgroups
  1046.  *
  1047.  * This routine will show the window that opens into the current
  1048.  * list of newsgroup lines.  Current is the one that will be
  1049.  * highlighted.  The global variable scrnpos is used to indicate
  1050.  * where this line is on the screen, with 0 being at the top line.
  1051.  * 
  1052.  * The intention of this routine is that it should be used whenever
  1053.  * there is a major change to the cursor position within the list.
  1054.  * This may be the result of a search, or jumping to the top or
  1055.  * bottom of the file, or using page up or page down keys.  The
  1056.  * desired behaviour is that the highlighted line should stay
  1057.  * roughly in the same position on the screen when this move occurs.
  1058.  * We can calculate the relative position of the current line by
  1059.  * subtracting the scrnpos from current to begin the index.
  1060.  */
  1061.  
  1062. void 
  1063. showlist(current,flag)
  1064. int current;
  1065. int flag;
  1066. {
  1067.     int position, counter;
  1068.     int scrn;
  1069.  
  1070.     scrn = eeplines - 1;
  1071.     if ( flag > 0 ) {
  1072.         if (current + scrn > c_active) {
  1073.             top = c_active - scrn;
  1074.         } else if ( current < top || current >= top + scrn ) {
  1075.             top = current - scrn / 2;
  1076.         }
  1077.         if ( top < 0 ) top = 0;
  1078.         scrnpos = current - top;
  1079.     }
  1080.     position = current - scrnpos;
  1081.     counter = 0;
  1082.     while (counter < scrn) {
  1083.         move(counter, 0);
  1084.         if ((position >= 0) && (position < c_active)) {
  1085.             if (counter == scrnpos) {
  1086.                 if (!eepoint)
  1087.                     standout();
  1088.                 if (aptr->mark == 0)
  1089.                     printw("->");
  1090.                 else
  1091.                     printw("*>");
  1092.             } else if (aptr->mark == 0)
  1093.                 printw("  ");
  1094.             else
  1095.                 printw("* ");
  1096.             aptr = act[position];
  1097.                 /* Show whether subscribed or not */
  1098.             switch (aptr->status) {
  1099.             case ':':
  1100.                 printw("+");          /* subscribed */
  1101.                 break;
  1102.             case '!':
  1103.                 printw(" ");          /* unsubscribed */
  1104.                 break;
  1105.             default:
  1106.                 printw("?");          /* mystery! */
  1107.             }
  1108.             printw("%.*s ", namecols, pad(aptr->name, namecols));
  1109.             printw("%.*s ", desccols, pad(aptr->desc, desccols));
  1110.             move(counter, 0);
  1111.             if ((counter == scrnpos) && !eepoint)
  1112.                 standend();
  1113.         } else
  1114.             printw("%.79s", pad((char *) NULL, 79));
  1115.         position++;
  1116.         counter++;
  1117.     }
  1118.     if ( flag == 0 ) {
  1119.         move(scrn, 0);
  1120.         deleteln();
  1121.         printw("There are %d available newsgroups", c_active);
  1122.         move(scrn, 60);
  1123.         printw("Press ? for Help");
  1124.     }
  1125.     move(scrnpos, flag);
  1126.     refresh();
  1127. }
  1128.